import {getFieldMixinDefMap} from "./render";
import {evalStr} from "./evalGlo";

/**
 *
 * @returns {(function(*, {props?: *}=): (*))|*}
 */
export function createFieldMixin() {
  let fieldMixinDefMap = getFieldMixinDefMap()
  return function (propConfig, {props = {}, extData = {}} = {}) {
    let ui = ZY.lodash.get(propConfig, ['ui'], {})
    let widget = ZY.lodash.get(propConfig, ['ui', 'widget'], '')
    if (ui.custom) {
      widget = propConfig?.ui?.cusWidget ?? ''
      // return {
      //   template: `<div>${widget}</div>`,
      //   data() {
      //     return {
      //       ui: propConfig.ui,
      //     }
      //   }
      // }
    }
    if (widget && fieldMixinDefMap.has(widget)) {
      return fieldMixinDefMap.get(widget).create(propConfig, props, extData)
    }
    return {
      template: `<div>${widget}</div>`,
      data() {
        return {
          ui: propConfig.ui,
        }
      }
    }
  }
}

export let baseZFormComMixin = {
  inject: ['curFormCon'],
  data() {
    return {
    }
  },
  methods: {
    async zfield__initDataSource({onRequest, lazyLoad} = {}) {
      let zFormMeta = globalThis.ZForm.getZFormMeta(this)
      let globalVars = zFormMeta?.request?.globalVars
      let rawModel = this.curFormCon.getRawModel()

      // console.log('zfield__initDataSource', zFormMeta, rawModel )
      // console.log(rawModel, this.curFormCon)

      let ctx = {
        M(key) {
          let s_path  = ZY.getObjPathFromPathArr(key)
          // console.log(s_path)
          return ZY.deepGet(rawModel, s_path)
        },
        $G: globalVars ? globalVars() : {}
      }

      let optionsUrl = ZY.lodash.get(this.ui, 'widgetConfig.optionsUrl')
      let optionsWidgetConfig = ZY.lodash.get(this.ui, 'widgetConfig') ?? {}
      let optionsUI = this.ui ?? {}

      // console.log(optionsUrl)
      if (lazyLoad) {
        return;
      }

      if (optionsUI.enableRemote && onRequest) {
        await  onRequest({ config: optionsWidgetConfig, url: '', ui: optionsUI}, {type: 'options', ui: this.ui, ctx: this})
        return;
      }

      if (optionsUrl  && onRequest) {
        await  onRequest({ config: optionsWidgetConfig, url: optionsUrl, ui: optionsUI}, {type: 'options', ui: this.ui, ctx: this})

        return;
      }


      let TYPE_ENUMS = {
        "0": 'get',
        "1": 'post'
      }
      let source = ZY.lodash.get(this.ui, 'source')
      if (source) {

        // console.log('zfield__initDataSource', source )
        try {
          let sourceObj = ZY.JSON5.parse(source)
          if (sourceObj && sourceObj.data && sourceObj.data.obj && sourceObj.data.type) {
            if (sourceObj.data.type === 'API') {
              let source = sourceObj.data.obj[sourceObj.data.type]
              if (source.apis && source.apis[source.name]) {
                let apiConfig = source.apis[source.name]
                let origin = apiConfig.origin
                let parameters = apiConfig.parameters
                let returnUUID = apiConfig.origin.returnUUID
                let returnValueUUID = apiConfig.origin.returnValueUUID
                let returnParameters = apiConfig.origin.returnParameters
                // console.log(returnParameters)
                // apiConfig.returnUUID  = apiConfig.origin.returnUUID
                // apiConfig.returnValueUUID  = apiConfig.origin.returnValueUUID
                apiConfig.request = {}
                // GET,POST
                apiConfig.request.method = TYPE_ENUMS[origin.interfaceMethods]
                apiConfig.request.url = origin.interfacePath
                let sendObj = {}
                parameters.forEach(parameter => {
                  // console.log(parameter)
                  if (parameter.hasOwnProperty('fxValue')) {
                    try {
                      let obj = ZY.JSON5.parse(parameter.fxValue)
                      if (typeof obj === 'string') {
                        obj = ZY.JSON5.parse(obj)
                      }

                      let evalStr = obj.textContent
                      try {
                        let ret = ZY_EXT.eval5(evalStr, ctx)

                        sendObj[parameter.fieldName] = ret
                      } catch (e) {
                        console.log('eval5 err', e)
                      }
                      // console.log(ret)

                    } catch (e) {
                      console.log('parse fxValue err', e)
                    }
                  }
                  else if (parameter.hasOwnProperty('value')) {
                    sendObj[parameter.fieldName] = parameter.value
                  }
                  else {
                    //
                  }
                  // console.log(sendObj[parameter.fieldName] )
                })
                if (apiConfig.request.method === 'get') {
                  apiConfig.request.params = sendObj
                }
                if (apiConfig.request.method === 'post') {
                  apiConfig.request.data = sendObj
                }
                apiConfig.request.headers = {
                }
                // if (origin.tokeIs) {
                //   apiConfig.request.headers.token = 'mock token'
                // }
                if (onRequest) {
                  await onRequest(apiConfig, origin)
                }
                // console.log(apiConfig)
              }
              // console.log(source)
            }
          }
        } catch (e) {
          console.log('zfield__initDataSource err', e,  source)
        }
      }
    }
    ,
    zfeild__buildOptions(ui, optArr) {
      let _widget = ZY.lodash.get(ui, ['widgetConfig']) ?? {}
      let source = ZY.lodash.get(ui, ['source'])
      let options = []
      if (_widget.options) {
        try {
          let opt = _widget.options
          options = options.concat(opt)
        } catch (e) {
          //
        }
      }
      if (_widget.options2) {
        try {
          let opt = ZY.JSON5.parse(_widget.options2)
          options = options.concat(opt)
        } catch (e) {
          //
        }
      }
      if (_widget.tree_options) {
        try {
          let opt = ZY.JSON5.parse(_widget.tree_options)
          options = options.concat(opt)
          // console.log(options)
        } catch (e) {
          //
        }
      }

      if (source) {
        try {
          let opt = ZY.JSON5.parse(source)
          let data = opt.data
          // options = options.concat(opt)
          if (data.type === 'STATIC') {
            let cur = data.obj[data.type]
            if (cur.value) {
              let opt = ZY.JSON5.parse(cur.value)

              // console.log('buildOptions', opt)
              options = options.concat(opt)
            }
          }
        } catch (e) {
          //
        }
      }
      if (optArr) {
        options = options.concat(optArr)
      }
      // console.log(_widget, widgetConfig2)
      return options
    }
  }
}

/**
 * 将配置文件转换为template
 * @param propConfig {{}}
 */
export function resolveEventsToObj(propConfig = {}) {

  let events = ZY.lodash.get(propConfig, 'server.events')
  try {
    let eventsObj = ZY.JSON5.parse(events)
    // console.log(eventsObj)
    if (Array.isArray(eventsObj.events)){
      return eventsObj.events
    }
  } catch (e) {
    return []
  }
}

/**
 * 将配置文件转换为template
 * @param propConfig {{}}
 */
export function resolveEventsToTemplate(propConfig = {}) {
  let events = resolveEventsToObj(propConfig)
  let tpl = ''
  events.forEach(eventItem => {
    let type = eventItem.type
    tpl = tpl + `v-on:${type}="zfield__events['${type}']"`
  })
  return tpl
}


/**
 *
 * @param name
 * @param cmFieldTpl
 * @param prop_config
 * @param globalUIConfig
 * @returns {Promise<unknown>|{mixins: ({data(): {}, methods: {zfield__initDataSource({onRequest: *}=): Promise<void>, zfeild__buildOptions(*, *): *[]}, inject: string[]}|*)[], data(): {zfield__highConfig: *, zfield__events: {}, zfield__propConfig: {}, zfield__v: number, zFormMeta: {}, zfield__s: number}, methods: {zfield__setAndUpdate(*): void, zfield__setVal(*): void, zfield__req(*, {event?: *, options?: *}=): Promise<unknown>, zfield__onInput(*): void}, created(): void, beforeMount(): void, name, inject: string[]}|{zfield__highConfig: *, zfield__events: {}, zfield__propConfig: {}, zfield__v: number, zFormMeta: {}, zfield__s: number}}
 */
export function createTemCmFieldCom(name, cmFieldTpl, {prop_config = {}, globalUIConfig = {}, outerProps = {}} = {}) {
  // console.log(prop_config)

  let eventArr = resolveEventsToObj(prop_config)
  // console.log(eventArr)

// console.log('local createTemCmFieldCom')
  return {
    name: name,
    mixins: [
      baseZFormComMixin,
      cmFieldTpl
    ],
    inject: ['CurCmField', 'ZFormTemplateIns'],
    data() {
      let self = this
      let zfield__events = {}
      eventArr.forEach(eventItem => {
        // console.log(eventItem)
        if (eventItem.action) {
          let fun = ZY.JSON5.parse(ZY.JSON5.parse(eventItem.action))
          zfield__events[eventItem.type] = function () {
            let ret = evalStr(fun.textContent, {
              ALERT: function(v) {
                // alert(v)
                self.$message.info(v)
              }
            })
            // console.log(1)
          }
          // console.log(fun)
        }
      })

      // console.log(globalUIConfig)
      return {
        zfield__outerProps: outerProps,
        zfield__s: 1,
        zfield__globalUIConfig: globalUIConfig,
        zfield__v: Date.now(),
        zfield__propConfig: prop_config,
        zfield__highConfig: prop_config.server,
        zfield__events,
        zFormMeta: {},
      }
    },
    computed: {
      zfield__listeners: function () {
        var vm = this
        // console.log(vm)
        // `Object.assign` 将所有的对象合并为一个新对象
        return Object.assign({},
          // 我们从父级添加所有的监听器
          this.$listeners,
          // 然后我们添加自定义监听器，
          // 或覆写一些监听器的行为
          {
            // 这里确保组件配合 `v-model` 的工作
            blur: function (event) {
              // console.log('eveev', event)
              vm.zfield__emit('com:blur', {

              }, event)
            },
            focus: function (event) {
              // console.log('eveev', event)
              vm.zfield__emit('com:focus', {

              }, event)
            },
            change: function (event) {
              // console.log('eveev', event)
              vm.zfield__emit('com:change', {

              }, event)
            },
            // input: function (event) {
            //   // console.log(event)
            //   vm.$emit('input', event.target.value)
            // }
          }
        )
      },
      zfield__readonly() {
        let readonly = this.zfield__globalUIConfig?.globals?.readonly

        if (this.ZFormTemplateIns) {
          let ZFormTemplateInsProps = this.ZFormTemplateIns.getProps();
          // console.log('ZFormTemplateInsProps', ZFormTemplateInsProps)
          if (ZFormTemplateInsProps.readonly) {
            return true
          }
        }

        if (readonly) {
          return true
        }
      },
      zfield__disabled() {
        // console.log('this', this.ui)

        if (this.ZFormTemplateIns) {
          let ZFormTemplateInsProps = this.ZFormTemplateIns.getProps();
          // console.log('ZFormTemplateInsProps', ZFormTemplateInsProps)
          if (ZFormTemplateInsProps.disabled) {
            return true
          }
        }

        if (this?.ui?.disable) {
          return this.ui.disable(this)
        }
        let disabled = this.zfield__globalUIConfig?.globals?.disabled
        if (disabled) {
          return true
        }
      },
    },
    methods: {
      // onInput(v) {
      //   this.CurCmField.onInput(v)
      // },
      zfield__setAndUpdate(v) {
        this.zfield__setVal(v)
        this.zfield__onInput(v)
      },
      zfield__onInput(v) {
        this.zfield__emit('com:input', {
          value: v
        })
        this.CurCmField.onInput(v)
      },
      zfield__emit(name, v = {}, originEvent) {
        // console.log(this.curFormCon.zform__callEvent)
        // console.log(this.zfield__outerProps)
        if (v ) {
          v.self_path = this.zfield__outerProps.self_path
          v.config =  this.zfield__propConfig
          v.ctx = this
          v.curFormCon = this.curFormCon
          v.props = this.zfield__outerProps
          v.pathArr = this.zfield__outerProps.pathArr
        }
        this.curFormCon.listenEvent(name, v, originEvent)
      },
      zfield__setVal(v) {
        this.value = v
      },
      zfield__req(zFormMeta, {event = '', options = {api: ''}} ={}) {
        return new Promise(async (resolve) => {
          let request =  zFormMeta?.request
          if (request && request[event]) {

            let [err, res] = await  ZY.awaitTo(request[event](options))
            if (err) {
              console.log('zfield__req err', err)
            } else {
              console.log('zfield__req', res)
              resolve(res)
            }

          }
        })
      }
    },
    created() {
      this.zFormMeta = globalThis.ZForm.getZFormMeta(this)
      // console.log('createTemCmFieldCom ins created')
    },
    beforeMount() {
      // console.log( this.zFormMeta)
      // console.log('cm-field-core beforeMount')
      this.CurCmField.register(this)
      this.value = this.CurCmField.initValue(this.value)
      // 如果时空值可以使用默认值
      // console.log(prop_config)
      if (this.value === null || typeof this.value === 'undefined') {
        if (prop_config.defaultVal) {
          let $G = {}
          if (this.zFormMeta && this.zFormMeta.request && this.zFormMeta.request.globalVars) {
            $G = this.zFormMeta.request.globalVars()
          }

          // console.log('prop_config defaultVal', this.zFormMeta, prop_config.defaultVal, $G)
          try {
            let obj = ZY.JSON5.parse(prop_config.defaultVal)
            try {
              if (obj && obj.textContent) {
                let ret = evalStr(obj.textContent, {
                  $G
                })
                this.value = ret
                // console.log(ret)
              }
            } catch (e) {
              console.log('eval err', e)
            }
          } catch (e) {
            console.log('prop_config err', e)
            if (e && e.message && e.message.indexOf('JSON5') > -1) {

              this.value = prop_config.defaultVal
            }
          }
          // this.value = prop_config.defaultVal
        }
      }
    },
  }
}

function createTemCmFieldCom2(name, cmFieldTpl, prop_config) {
  return {
    name: name,
    mixins: [
      baseZFormComMixin,
      cmFieldTpl
    ],
    methods: {
      // onInput(v) {
      //   this.CurCmField.onInput(v)
      // },
      zfield__onInput(v) {

      },
      zfield__setVal(v) {
        this.value = v
      }
    },
    beforeMount() {
      // console.log(this.CurCmField)

    },
  }
}

/**
 * 提供创建动态组件的方法
 * @param widgetUUID
 * @param prop_config
 * @param extData
 * @returns {{mixins: ({data(): {}, methods: {zfeild__buildOptions(*): *[]}}|*)[], methods: {zfield__setVal(*): void, zfield__onInput(*): void}, beforeMount(): void, name, inject: string[]}}
 */
export function createDymFormWidgetDef(widgetUUID, prop_config, extData = {}) {
  let fieldMixin = createFieldMixin()
  // console.log(fieldMixin)
  let cmFieldTpl = fieldMixin(prop_config, {extData})

  return  createTemCmFieldCom2(widgetUUID, cmFieldTpl, prop_config)
}
